package com.rentong.common;

import com.rentong.json.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.io.IOException;
import java.sql.Time;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author ZXY
 * @ClassName: RedisCommons
 * @Description: redis工具类
 * @date 2016/6/30 16:40
 */
public class RedisUtils {
    private Logger logger = LoggerFactory.getLogger(getClass());

    private RedisTemplate redisTemplate;

    public RedisUtils(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    //设置某日超时天数
    private int defaultTimeoutDay = 1;

    //设置超时时间
    private String defaultTimeoutTimes = "03:00:00";


    /**
     * redis set集合有过期时间
     *
     * @param key     reids key
     * @param value   需要缓存的数据
     * @param timeOut 超时时长
     * @param unit    超时时长单位
     * @throws IOException
     */
    public boolean set(String key, Object value, long timeOut, TimeUnit unit) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(key);
                boundValueOperations.set(value);
                return boundValueOperations.expire(timeOut, unit);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return false;
    }

    /**
     * redis set集合有默认过期时间
     *
     * @param key   reids key
     * @param value 需要缓存的数据
     */
    public boolean set(String key, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(key);
                boundValueOperations.set(value);
                return boundValueOperations.expireAt(getDefaultExpireDate());
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return false;
    }

    /**
     * set集合可设置过期时间
     *
     * @param key
     * @param value
     * @param date
     */
    public boolean set(String key, Object value, Date date) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(key);
                boundValueOperations.set(value);
                boundValueOperations.expireAt(date);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return false;
    }

    /**
     * set集合 没有过期时间
     *
     * @param key
     * @param value
     */
    public void setNoExpire(String key, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundValueOperations boundValueOperations = redisTemplate.boundValueOps(key);
                boundValueOperations.set(value);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * get
     *
     * @param key
     * @param clazz
     * @return
     */
    public <T> T get(String key, Class<T> clazz) {
        try {
            return (T) redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            logger.error("get error={}", e);
        }
        return null;
    }

    /**
     * getIncr 解决redis increment GUG 取值问题
     *
     * @param key
     * @param clazz
     * @return
     */
    public <T> T getIncr(String key, Class<T> clazz) {
        try {
            redisTemplate.setValueSerializer(new StringRedisSerializer());
            String objectJson = (String) redisTemplate.opsForValue().get(key);
            redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
            if (StringUtils.isBlank(objectJson)) {
                return null;
            }
            return JsonUtils.readValue(objectJson, clazz);
        } catch (Exception e) {
            logger.error("get error={}", e);
        }
        return null;
    }


    /**
     * 根据key删除
     *
     * @param key
     */
    public void delete(String key) {
        try {
            redisTemplate.delete(key);
        } catch (Throwable e) {
            logger.error("delete error:", e);
        }
    }


    /**
     * 根据key删除
     *
     * @param key
     */
    public void hDelete(String key, String hKey) {
        try {
            BoundHashOperations operations = redisTemplate.boundHashOps(key);
            operations.delete(hKey);
        } catch (Exception e) {
            logger.error("delete error:", e);
        }
    }

    /**
     * get  List集合
     *
     * @param key
     * @param clazz
     * @return
     */
    public <T> List<T> getList(String key, Class<T> clazz) {
        try {
            return (List<T>) redisTemplate.opsForValue().get(key);
        } catch (Exception e) {
            logger.error("get error={}", e);
        }
        return null;
    }

    /**
     * 存放hash集合可设置过期时间
     *
     * @param key
     * @param value
     * @param date
     */
    public void hSet(String key, String hKey, Object value, Date date) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.put(hKey, value);
                operations.expireAt(date);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 存放hash集合可设置过期时间
     *
     * @param key
     * @param hKey
     * @param value
     * @param timeOut
     * @param unit
     */
    public void hSet(String key, String hKey, Object value, long timeOut, TimeUnit unit) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.put(hKey, value);
                operations.expire(timeOut, unit);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 存放hash集合使用默认失效时间
     *
     * @param key
     * @param hKey
     * @param value
     */
    public void hSet(String key, String hKey, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.put(hKey, value);
                operations.expireAt(getDefaultExpireDate());
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 存放hash集合
     *
     * @param key
     * @param hKey
     * @param value
     */
    public void hSetNoExpire(String key, String hKey, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.put(hKey, value);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 获得默认失效时间
     */
    private Date getDefaultExpireDate() {
        return DateUtils.getTomorrow();
    }

    /**
     * 存放Map集合 有默认失效时间
     *
     * @param key
     * @param map
     * @param value
     */
    public void hSetAll(String key, Map<String, String> map, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.putAll(map);
                operations.expireAt(getDefaultExpireDate());
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 存放Map集合 有默认失效时间
     *
     * @param key
     * @param map
     * @param value
     * @param timeout
     * @param unit
     */
    public void hSetAll(String key, Map<String, String> map, Object value, long timeout, TimeUnit unit) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.putAll(map);
                operations.expire(timeout, unit);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }

    /**
     * 存放Map集合 有默认失效时间
     *
     * @param key
     * @param map
     * @param value
     */
    public void hSetAllNoExpire(String key, Map<String, String> map, Object value) {
        try {
            if (ObjectUtils.isNotEmpty(value)) {
                BoundHashOperations operations = redisTemplate.boundHashOps(key);
                operations.putAll(map);
            }
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
    }


    /**
     * hash获取自增 getIncr 解决redis increment GUG 取值问题
     *
     * @param key
     * @param hKey
     * @param clazz
     * @return
     */
    public <T> T hGetIncr(String key, String hKey, Class<T> clazz) {
        try {
            redisTemplate.setHashValueSerializer(new StringRedisSerializer());
            String objectJson = (String) redisTemplate.opsForHash().get(key, hKey);
            redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
            if (StringUtils.isBlank(objectJson)) {
                return null;
            }
            return JsonUtils.readValue(objectJson, clazz);
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return null;
    }

    /**
     * hash存放
     *
     * @param key
     * @param hKey
     * @param clazz
     * @return
     */
    public <T> T hGet(String key, String hKey, Class<T> clazz) {
        try {
            return (T) redisTemplate.opsForHash().get(key, hKey);
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return null;
    }

    /**
     * 获得hash全部值
     *
     * @param key
     * @return
     */
    public Map<String, Object> hGetAll(String key) {
        try {
            return redisTemplate.opsForHash().entries(key);
        } catch (Exception e) {
            logger.error("set error={}", e);
        }
        return null;
    }

    /**
     * set 集合式存放
     *
     * @param key
     * @param value
     * @param score
     * @return
     */
    public boolean zAdd(String key, Object value, double score) {
        BoundZSetOperations<String, Object> opt = redisTemplate.boundZSetOps(key);
        return opt.add(value, score);
    }

    /**
     * 根据下标大小获取Set
     *
     * @param key
     * @param min
     * @param max
     * @param clazz
     * @return
     */
    public <T> Set<T> zrange(String key, double min, double max, Class<T> clazz) {
        BoundZSetOperations<String, Object> opt = redisTemplate.boundZSetOps(key);
        Set<Object> set = opt.rangeByScore(min, max);
        Set<T> result = new LinkedHashSet<T>(set.size());
        for (Object obj : set) {
            result.add((T) obj);
        }
        return result;
    }

    /**
     * set 删除
     *
     * @param key
     * @param min
     * @param max
     */
    public void zDelByScore(String key, double min, double max) {
        BoundZSetOperations<String, String> opt = redisTemplate.boundZSetOps(key);
        opt.removeRangeByScore(min, max);
    }

    /**
     * 自增带有效时间的
     *
     * @param key
     * @param value
     * @return
     */
    public int incr(String key, int value, long timeout, TimeUnit unit) {
        BoundValueOperations operations = redisTemplate.boundValueOps(key);
        Long i = operations.increment(value);
        operations.expire(timeout, unit);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }


    /**
     * 自增指定失效时间点
     *
     * @param key
     * @param value
     * @return
     */
    public int incr(String key, int value, Date date) {
        BoundValueOperations operations = redisTemplate.boundValueOps(key);
        Long i = operations.increment(value);
        operations.expireAt(date);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }

    /**
     * 自增
     *
     * @param key
     * @param value
     * @return
     */
    public int incr(String key, int value) {
        BoundValueOperations operations = redisTemplate.boundValueOps(key);
        Long i = operations.increment(value);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }


    /**
     * 自减
     *
     * @param key
     * @param value
     * @return
     */
    public int derc(String key, int value) {
        BoundValueOperations operations = redisTemplate.boundValueOps(key);
        Long i = operations.increment(-value);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }

    /**
     * hash自增
     *
     * @param key
     * @param value
     * @return
     */
    public int hIncr(String key, String hKey, int value) {
        BoundHashOperations operations = redisTemplate.boundHashOps(key);
        Long i = operations.increment(hKey, value);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }

    /**
     * hash自增指定失效时间点
     *
     * @param key
     * @param value
     * @return
     */
    public int hIncr(String key, String hKey, int value, Date date) {
        BoundHashOperations operations = redisTemplate.boundHashOps(key);
        Long i = operations.increment(hKey, value);
        operations.expireAt(date);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }

    /**
     * hash自减
     *
     * @param key
     * @param value
     * @return
     */
    public int hDecr(String key, String hKey, int value) {
        BoundHashOperations operations = redisTemplate.boundHashOps(key);
        Long i = operations.increment(hKey, -value);
        if (i != null) {
            return i.intValue();
        }
        return 0;
    }

    /**
     * 队列顶部插入数据
     *
     * @param key
     * @param obj
     */
    public long inPop(String key, Object obj) {
        BoundListOperations operations = redisTemplate.boundListOps(key);
        return operations.leftPush(obj);
    }

    /**
     * 队列底部插入数据
     *
     * @param key
     * @param obj
     */
    public long inBottomPop(String key, Object obj) {
        BoundListOperations operations = redisTemplate.boundListOps(key);
        return operations.rightPush(obj);
    }

    /**
     * 队列顶部插入数据
     *
     * @param key
     * @param obj
     */
    public long inPop(String key, Object obj, Date date) {
        long result = 0;
        BoundListOperations operations = redisTemplate.boundListOps(key);
        result = operations.leftPush(obj);
        operations.expireAt(date);
        return result;
    }

    /**
     * 队列插入list数据
     *
     * @param key
     * @param objs
     */
    public long inPopAll(String key, Date date, Object... objs) {
        long result = 0;
        BoundListOperations operations = redisTemplate.boundListOps(key);
        result = operations.leftPushAll(objs);
        operations.expireAt(date);
        return result;
    }

    /**
     * 队列插入list数据
     *
     * @param key
     * @param objs
     */
    public long inPopAll(String key, Object... objs) {
        long result = 0;
        BoundListOperations operations = redisTemplate.boundListOps(key);
        result = operations.leftPushAll(objs);
        return result;
    }

    /**
     * 队列底部取出
     *
     * @param key
     * @param obj
     */
    public <T> T getBottomPop(String key, Object obj, Class<T> clazz) {
        BoundListOperations operations = redisTemplate.boundListOps(key);
        return (T) operations.rightPop();
    }

    /**
     * 队列顶部取出
     *
     * @param key
     * @param obj
     */
    public <T> T getTopPop(String key, Object obj, Class<T> clazz) {
        BoundListOperations operations = redisTemplate.boundListOps(key);
        return (T) operations.leftPop();
    }

    /**
     * 查询List
     * @param key
     * @return
     */
    public <T> List<T> getListByKey(Integer page,Integer rows, String key,Class<T> clazz){
        BoundListOperations listRedisTemplate = redisTemplate.boundListOps(key); //获取key的名称
        //查询list从0开始,到index位的值,如果是-1,则表示查询出来所有
        List<T>  range = listRedisTemplate.range(page, rows);
        return range;
    }

    /**
     * 查询值string在队列中的位置
     * @param key
     * @param value
     * @return
     */
    public long getListIndex(String key,String  value) {
        BoundListOperations listRedisTemplate = redisTemplate.boundListOps(key);
        List range = listRedisTemplate.range(0, -1);
        for (int i = 0; i < range.size(); i++) {
            String val=range.get(i).toString();
            if(val.equals(value)){
               return i+1;
            }
        }
        return  -1;
    }

    /**
     * 删除值为object
     * @param key
     * @param object
     * @return
     */
    public String deleteByValue(String key,Object  object) {
        BoundListOperations listRedisTemplate = redisTemplate.boundListOps(key);

        return listRedisTemplate.remove(1,object).toString();

    }

    /**
     * 将下标为index的位置的值修改为object
     * @param key
     * @param object
     * @param index
     */
    public void setIndex(String key,Object object,long index){
        BoundListOperations listRedisTemplate = redisTemplate.boundListOps(key);
        listRedisTemplate.set(index,object);
    }

    /**
     * 根据下标获取List中的元素
     * @param key
     * @param index
     */
    public Object getIndex(String key,long index){
        BoundListOperations listRedisTemplate = redisTemplate.boundListOps(key);
        return listRedisTemplate.index(index);
    }

    /**
     * 放入String类型的值
     * @param key
     * @param value
     */
    public void set(String key,String value){
        redisTemplate.opsForValue().set(key,value);
    }

    /**
     * 放入String类型的值，包含失效时间
     * @param key
     * @param value
     */
    public void setTimes(String key, String value, Long timeOut, TimeUnit unit){
        redisTemplate.opsForValue().set(key,value,timeOut,unit);
    }

    /**
     * 取出String类型的值
     * @param key
     */
    public String get(String key){
        return (String) redisTemplate.opsForValue().get(key);
    }

}


